﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace BackgroundActionPool_Test {
    [TestClass]
    public class MainRunningTest {
        private int Progress { get; set; }
        private String CurrentStatusTask { get; set; }

        public ManualResetEvent WaitAllDone {
            get { return m_waitAllDone; }
        }

        private ManualResetEvent m_waitAllDone = new ManualResetEvent(false);

        [TestMethod]
        public void Test_Pool () {
            ActionSuccessPool pool = new ActionSuccessPool();
            var thingsToDo = CollectThingsToDo();
            foreach (var actionToDo in thingsToDo) {
                actionToDo.OnDone += actionToDo_OnDone;
                pool.Add(actionToDo, actionToDo.StatusText);
            } // foreach end
            pool.OnNextProgress += pool_OnNextProgress;
            pool.OnAllDone += pool_OnAllDone;
            pool.Run();
            WaitAllDone.WaitOne(2000 * 10);
        }

        void actionToDo_OnDone (object sender, BackgroundTask.ActionDoneEventArgs<bool> e) {
            if (!e.Result) {
                throw new Exception();
            }
        }

        void pool_OnAllDone (object sender, EventArgs e) {
            CurrentStatusTask = "Done all.";
            Progress = 100;
            Print();
            WaitAllDone.Set();
        }

        void Print() {
            Debug.WriteLine(String.Format("Performing: {0}", CurrentStatusTask));
            Debug.WriteLine(String.Format("Percentage: {0}%", Progress));
            Debug.WriteLine("########");
        }

        void pool_OnNextProgress (object sender, EventArgs e) {
            var pool = (sender as ActionSuccessPool);
            Assert.IsNotNull(pool);
            CurrentStatusTask = pool.CurrentProgressName;
            Progress = pool.CurrentPercentage;
            Print();
        }

        private IEnumerable<VariousActionWithResult> CollectThingsToDo() {
            List<VariousActionWithResult> ret = new List<VariousActionWithResult>();
            
            // generate actions
            var openDb = new VariousActionWithResult(Do, DummyAction)
                {
                    StatusText = "Opening database"
                };

            var createTables = new VariousActionWithResult(Do, DummyAction)
                {
                    StatusText = "Creating database tables"
                };

            var createUsers = new VariousActionWithResult(Do, DummyAction)
                {
                    StatusText = "Installing users"
                };

            var dbClose = new VariousActionWithResult(Do, DummyAction) {
                StatusText = "Closing database"
            };

            var dbCheckForUpdates = new VariousActionWithResult(Do, DummyAction) {
                StatusText = "Checking for updates"
            };

            ret.AddRange(new List<VariousActionWithResult>()
                {
                    openDb,
                    createTables,
                    createUsers
                });
            return ret;
        }

        private void DummyAction () {
            Random rand = new Random();
            Thread.Sleep(rand.Next(500, 2000));
        }

        private bool Do(Action action) {
            try {
                action.Invoke();
            } // try end
            catch {
                return false;
            } // catch end
            return true;
        }
    }
}
